package bma.common.langutil.jmshell.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import bma.common.langutil.core.StringUtil;
import bma.common.langutil.core.ValueUtil;
import bma.common.langutil.jmshell.JMShellUtil;
import bma.common.langutil.jmshell.Session;
import bma.common.langutil.jmshell.SessionCloseListener;
import bma.common.langutil.jmshell.cmdopt.CommandOptionParser;
import bma.common.langutil.jmshell.command.AbstractSimpleCommandProcessor;
import bma.common.langutil.log.LogbackUtil;
import ch.qos.logback.classic.Level;

public class UtilLogCommand extends AbstractSimpleCommandProcessor {

	public static final String DATA_KEY = "@util_log";

	public static class LogItem {
		public String type;
		public String level;
		public String oldLevel;
	}

	public static class LogInfo {
		public SessionCloseListener listener;
		public List<LogItem> settings = Collections
				.synchronizedList(new ArrayList<LogItem>());
	}

	public UtilLogCommand() {
		super("log");
		setArgsTips("[type] [level]");
	}

	@Override
	public CommandOptionParser createCommandOption(Session session) {
		CommandOptionParser r = new CommandOptionParser();
		r.addBooleanOption('r', "reset", "reset all log setting");
		r.addStringOption('d', "del", "delete log setting");
		r.addBooleanOption('l', "list", "list log setting");
		return r;
	}

	@Override
	public boolean processCommand(Session session, String cmd,
			CommandOptionParser options) {
		boolean r = options.getOptionValue("reset", Boolean.FALSE);
		if (r) {
			reset(session);
			return true;
		}
		String d = options.getOptionValue("del", "");
		if (ValueUtil.notEmpty(d)) {
			del(session, d);
			return true;
		}
		boolean l = options.getOptionValue("list", Boolean.FALSE);
		if (l) {
			list(session);
			return true;
		}
		String[] args = options.getRemainingArgs();
		if (args != null && args.length == 2) {
			set(session, args[0], args[1]);
			return true;
		}
		session.writeln(getHelp(session));
		return true;
	}

	public void reset(Session s) {
		LogInfo info = JMShellUtil.getData(s, DATA_KEY, LogInfo.class, false);
		if (info != null) {
			List<LogItem> tmp = new ArrayList<LogItem>(info.settings);
			info.settings.clear();
			for (LogItem o : tmp) {
				LogbackUtil.setLevel(o.type, o.oldLevel);
			}
		}
		s.writeln("log reset done");
	}

	public void del(Session s, String type) {
		LogInfo info = JMShellUtil.getData(s, DATA_KEY, LogInfo.class, false);
		if (info != null) {
			Iterator<LogItem> it = info.settings.iterator();
			while (it.hasNext()) {
				LogItem o = it.next();
				if (StringUtil.equals(type, o.type)) {
					LogbackUtil.setLevel(o.type, o.oldLevel.toUpperCase());
					s.writeln("log delete '" + type + "' done");
					it.remove();
					break;
				}
			}
		}
		s.writeln("[ERROR] log delete '" + type + "' fail, not found");
	}

	public void list(Session s) {
		LogInfo info = JMShellUtil.getData(s, DATA_KEY, LogInfo.class, false);
		s.writeln("[log]");
		if (info != null) {
			List<LogItem> tmp = new ArrayList<LogItem>(info.settings);
			for (LogItem o : tmp) {
				s.writeln(o.type + ": " + o.level + "(" + o.oldLevel + ")");
			}
		}
		s.writeln("[log end]");
	}

	public void set(Session s, String type, String level) {
		LogInfo info = JMShellUtil.getData(s, DATA_KEY, LogInfo.class, true);
		LogItem item = null;
		for (LogItem o : info.settings) {
			if (StringUtil.equals(o.type, type)) {
				item = o;
				break;
			}
		}
		if (item == null) {
			item = new LogItem();
			item.type = type;
			Level l = LogbackUtil.getLevel(type);
			item.oldLevel = l == null ? null : l.toString();
			info.settings.add(item);
		}
		LogbackUtil.setLevel(type, level.toUpperCase());
		item.level = level;
		s.writeln("log set '" + type + "' => " + level);
		if(info.listener==null) {
			info.listener = new SessionCloseListener() {
				
				@Override
				public void onClose(Session s) {
					reset(s);
				}
			};
			s.addCloseListener(info.listener);
		}
	}
	
}